/**************************************************************
Arise Engine		InputDeviceKeyboard.cpp

					E-mail:	arise_engine@mail.ru

created:			10.02.2007
last changes:		21.09.2008
**************************************************************/
#include "stdafx.h"


InputDeviceKeyboard::InputDeviceKeyboard()
{
	m_buffer_id = 0;
	ZeroMemory( m_keys_state[0], sizeof(m_keys_state[0]));
	ZeroMemory( m_keys_state[1], sizeof(m_keys_state[1]));
}
InputDeviceKeyboard::~InputDeviceKeyboard()
{
}


void InputDeviceKeyboard::ReadImmediateData()
{
	if(!GetDevice()) return;

    HRESULT hr;
	static DWORD size = sizeof(m_keys_state[0]);

    // Get the input's device state, and put the state in dims
    ZeroMemory( m_keys_state[m_buffer_id], size);
    hr = GetDevice()->GetDeviceState(size, m_keys_state[m_buffer_id]);
    if(FAILED(hr))
    {
		// DirectInput may be telling us that the input stream has been
		// interrupted.  We aren't tracking any state between polls, so
		// we don't have any special reset that needs to be done.
		// We just re-acquire and try again.

		// If input is lost then acquire or keep trying later
		hr = Acquire();

		// hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
		// may occur when the app is minimized or in the process of 
		// switching, so just try again later 
        return; 
    }

	GetLastEvent().Clear();

	int next_buffer_id = m_buffer_id + 1;
	if(next_buffer_id >= 2) next_buffer_id = 0;
	for(UINT i = 0; i < KEYBOARD_NUM_KEYS; i++)
	{
		if(m_keys_state[m_buffer_id][i] != m_keys_state[next_buffer_id][i])
		{
			InputEvent& event	= GetLastEvent();
			event.key_id		= i;
			
			if(m_keys_state[m_buffer_id][i] & 0x80)
				event.type = INPUT_EVENT_PRESSED;
			else
				event.type = INPUT_EVENT_RELEASED;
		}
	}

	m_buffer_id++;
	if(m_buffer_id >= 2) m_buffer_id = 0;
}


bool InputDeviceKeyboard::IsKeyPressed(DWORD key_code)
{
	if(m_keys_state[m_buffer_id][key_code] & 0x80) return true;

	return false;
}


void InputDeviceKeyboard::Release()
{
}


void InputDeviceKeyboard::BuildEvent(INPUT_EVENT_TYPE type, int key, int scan)
{
	//	winapi specific keyboard response, include uppercase, languages etc.
	//	used for generating input events for UI

	unsigned char kbstate[KEYBOARD_NUM_KEYS];
	GetKeyboardState(kbstate);

	m_ui_event.key_id		= scan;
	m_ui_event.device_id	= INPUT_DEVICE_ID_KEYBOARD;
	m_ui_event.type			= type;
	
	ToAscii(key, scan, kbstate, (unsigned short*) &m_ui_event.char_id, 0);
}
